using System;
using System.Collections.Generic;
using System.Text;

namespace Toenda.Foundation.Globalization.Holiday.HolidayCalenderFactories {
	/// <summary>
	/// Implements the Swiss HolidayCalendar
	/// </summary>
	public class SwissHolidayCalendarFactory : HolidayCalendarFactory {
		private static SwissHolidayCalendarFactory _instance;

		/// <summary>
		/// Gets the instance fo the specific holiday calendar
		/// </summary>
		/// <param name="year"></param>
		/// <param name="eventType"></param>
		/// <returns></returns>
		public static SwissHolidayCalendarFactory GetInstance(int year, HolidayEventType eventType) {
			if(_instance == null || year != _instance.CurrentYear) {
				_instance = new SwissHolidayCalendarFactory(year, eventType);
				return _instance;
			}

			return _instance;
		}

		/// <summary>
		/// Creates a new instance of <see cref="SwissHolidayCalendarFactory"/> and adds the specific holidays
		/// </summary>
		/// <param name="year"></param>
		/// <param name="eventType"></param>
		private SwissHolidayCalendarFactory(int year, HolidayEventType eventType) {
			this.CurrentYear = year;

			this.Initialize(eventType);
		}

		/// <summary>
		/// Initialize the calendar
		/// </summary>
		/// <param name="eventType"></param>
		public override void Initialize(HolidayEventType eventType) {
			base.Holidays = new List<Holiday>();
			base.Holidays.Add(new Holiday(true, new DateTime(this.CurrentYear, 1, 1), "New Year"));
			base.Holidays.Add(new Holiday(true, new DateTime(this.CurrentYear, 1, 2), "Berchtolds Day"));
			base.Holidays.Add(new Holiday(true, new DateTime(this.CurrentYear, 8, 1), "Swiss national day"));
			base.Holidays.Add(new Holiday(true, new DateTime(this.CurrentYear, 5, 1), "Labor Day"));
			//base.Holidays.Add(new Holiday(true, new DateTime(this.CurrentYear, 8, 15), "Assumption Day"));
			//base.Holidays.Add(new Holiday(true, new DateTime(this.CurrentYear, 11, 1), "All Saints' Day"));
			//base.Holidays.Add(new Holiday(true, new DateTime(this.CurrentYear, 12, 8), "Conception Day"));
			base.Holidays.Add(new Holiday(true, new DateTime(this.CurrentYear, 12, 25), "1. Christmas Day"));
			base.Holidays.Add(new Holiday(true, new DateTime(this.CurrentYear, 12, 26), "2. Christmas Day"));

			DateTime easterSunday = GetEasterSunday();
			base.Holidays.Add(new Holiday(false, easterSunday.AddDays(-2), "Good Friday"));
			base.Holidays.Add(new Holiday(false, easterSunday.AddDays(1), "Easter Monday"));
			base.Holidays.Add(new Holiday(false, easterSunday.AddDays(39), "Ascension Day"));
			base.Holidays.Add(new Holiday(false, easterSunday.AddDays(50), "Whit Monday"));
			//base.Holidays.Add(new Holiday(false, easterSunday.AddDays(60), "Feast of Corpus Christi"));

			switch(eventType) {
				case HolidayEventType.Trading:
				case HolidayEventType.Banking:
					break;

				case HolidayEventType.Currency:
				case HolidayEventType.Settlement:
					break;
			}
		}

		/// <summary>
		/// Get the Easter Sunday
		/// </summary>
		/// <returns></returns>
		private DateTime GetEasterSunday() {
			int g, h, c, j, l, i;

			g = base.CurrentYear % 19;
			c = base.CurrentYear / 100;
			h = ((c - (c / 4)) - (((8 * c) + 13) / 25) + (19 * g) + 15) % 30;
			i = h - (h / 28) * (1 - (29 / (h + 1)) * ((21 - g) / 11));
			j = (base.CurrentYear + (base.CurrentYear / 4) + i + 2 - c + (c / 4)) % 7;

			l = i - j;
			int month = (int)(3 + ((l + 40) / 44));
			int day = (int)(l + 28 - 31 * (month / 4));

			return new DateTime(base.CurrentYear, month, day);
		}
	}
}
